package com.dongbao.util;

import net.sourceforge.pmd.*;
import net.sourceforge.pmd.cli.PMDCommandLineInterface;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.renderers.XMLRenderer;
import net.sourceforge.pmd.util.ClasspathClassLoader;
import net.sourceforge.pmd.util.datasource.DataSource;
import net.sourceforge.pmd.util.datasource.FileDataSource;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class CodeInspectionUtil {

    public static String checkCode(String javaPath){
        String result;
        PMDConfiguration configuration = new PMDConfiguration();
        try{
            /* 首先我们创建一个PMDConfiguration. 这是当前指定规则集的唯一方法： */
            configuration.setMinimumPriority(RulePriority.MEDIUM);
//            configuration.setRuleSets("rulesets/java/quickstart.xml,rulesets/java/dhgrules.xml");
            /* TODO:只使用DHG顶置的规则 */
            configuration.setRuleSets("rulesets/java/dhgrules.xml");
            /* 为了支持类型解析，PMD 还需要访问已编译的类和依赖项。这称为“auxclasspath”，也在此处配置。注意：您可以:在 Unix 系统或;Windows 下指定多个以 分隔的类路径。 */
            configuration.prependClasspath("/home/workspace/target/classes:/home/.m2/repository/my/dependency.jar");
            /* 然后我们需要加载规则集。这是通过使用配置完成的，考虑到最低优先级： */
            RuleSetLoader ruleSetLoader = RuleSetLoader.fromPmdConfig(configuration);
            List<RuleSet> ruleSets = ruleSetLoader.loadFromResources(Arrays.asList(configuration.getRuleSets().split(",")));
            /* PMD 对DataSource. 您可以组装一个自己的列表FileDataSource，例如 */
            List<DataSource> files = Arrays.asList(new FileDataSource(new File(javaPath)));
            /* 对于报告，您可以使用内置渲染器，例如XMLRenderer或自定义渲染器实现 Renderer. 请注意，您必须通过设置合适的Writer并调用start(). PMD 运行后，您需要调用 end()和flush()。那么你的作者应该已经收到了所有的输出。 */
            StringWriter rendererOutput = new StringWriter();
            Renderer xmlRenderer = new XMLRenderer("UTF-8");
            xmlRenderer.setWriter(rendererOutput);
            xmlRenderer.start();
            /* 现在，所有的准备工作都完成了，可以执行 PMD 了。这是通过调用 PMD.processFiles(...). 此方法调用采用配置、规则集、要处理的文件和渲染器列表。如果您不想使用任何渲染器，请提供一个空列表。注意：需要明确关闭 auxclasspath。否则类或 jar 文件可能会保持打开状态并泄漏文件资源。 */
            PMD.processFiles(configuration, ruleSets, files, Collections.singletonList(xmlRenderer));
            /* 调用后，您需要通过end()和完成渲染器flush()。然后你可以检查渲染的输出。 */
            xmlRenderer.end();
            xmlRenderer.flush();
            result = rendererOutput.toString();
        }catch (Exception e){
            e.printStackTrace();
            result = null;
        }finally {
            ClassLoader auxiliaryClassLoader = configuration.getClassLoader();
            if (auxiliaryClassLoader instanceof ClasspathClassLoader) {
                try {
                    ((ClasspathClassLoader) auxiliaryClassLoader).close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    public static void main(String[] args) {
        CodeInspectionUtil.checkCode("D:\\work\\code\\test-project\\src\\main\\java\\com\\dongbao\\testproject\\test\\Example.java");
    }

}
